﻿using HMaker.Events;
using HMaker.Utils;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace HMaker.Controls
{

    public class PicSelector : Panel
    {
        /// <summary>
        /// 控件内的主图片框
        /// </summary>
        private readonly PictureBox _PictureBox;

        /// <summary>
        /// 背景图片内部存储
        /// </summary>
        private Bitmap _BG;

        #region 对外接口


        public Bitmap BG
        {
            get => _BG; set
            {
                _BG = value;
                _PictureBox.Image = value;
            }
        }

        /// <summary>
        /// 用于获取所有的图形控件
        /// </summary>
        public ControlCollection ShapeCollection => _PictureBox.Controls;

        public event ContextMenuNeededEventHandler OnContextMenuNeeded;
        public event SelectedAreaChangedEventHandler OnSelectedAreaChanged;

        public event PaintEventHandler BGPaint;
        public event MouseEventHandler BGMouseMove;

        #endregion

        public PicSelector()
        {
            AutoScroll = true;


            _PictureBox = new PictureBox
            {
                Size = Size.Empty,
                SizeMode = PictureBoxSizeMode.AutoSize,
                BorderStyle = BorderStyle.FixedSingle
            };
            _PictureBox.MouseDown += PictureBox_MouseDown;
            _PictureBox.MouseMove += PictureBox_MouseMove;
            _PictureBox.MouseUp += PictureBox_MouseUp;
            _PictureBox.Paint += PictureBox_Paint;
            _PictureBox.Click += _PictureBox_Click;
            Controls.Add(_PictureBox);
        }

        private void _PictureBox_Click(object sender, System.EventArgs e)
        {
            _PictureBox.Focus();
        }

        public void AddShape(ShapeControl ctrl)
        {
            ctrl.OnContextMenuNeeded += Ctrl_OnContextMenuNeeded;
            _PictureBox.Controls.Add(ctrl);
        }

        public void DeleteShape(ShapeControl ctrl)
        {
            ctrl.OnContextMenuNeeded -= Ctrl_OnContextMenuNeeded;
            _PictureBox.Controls.Remove(ctrl);
        }

        public void ClearShape()
        {
            foreach (Control control in _PictureBox.Controls)
            {
                if (control is ShapeControl c)
                {
                    c.OnContextMenuNeeded -= Ctrl_OnContextMenuNeeded;
                }
            }

            _PictureBox.Controls.Clear();
        }

        /// <summary>
        /// 屏幕坐标到图片坐标的转换
        /// </summary>
        /// <param name="point">屏幕坐标</param>
        /// <returns></returns>
        public Point PointToBG(Point point)
        {
            return _PictureBox.PointToClient(point);
        }

        /// <summary>
        /// 清除选择区域的虚框
        /// </summary>
        public void ClearRectSelect()
        {
            _MouseSelectRect = Rectangle.Empty;
            _PictureBox.Invalidate();
        }

        #region 控件绘制和行为定义
        private Point _MouseDownPos = Point.Empty;
        private Rectangle _MouseSelectRect = Rectangle.Empty;

        private bool _IsDrag = false;
        private readonly Pen _SelectPen = new Pen(Color.Gray) { DashStyle = DashStyle.DashDot };

        /// <summary>
        /// 处理子控件的弹出上下文菜单事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Ctrl_OnContextMenuNeeded(object sender, ContextMenuNeededEventArgs e)
        {
            e.LocationInBG = PointToClient(_PictureBox.PointToScreen(e.Location));
            OnContextMenuNeeded?.Invoke(sender, e);
        }

        private void PictureBox_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                _MouseDownPos = e.Location;
                _IsDrag = true;
            }
            else if (e.Button == MouseButtons.Right)
            {
                if (e.Clicks == 1)
                {
                    OnContextMenuNeeded?.Invoke(this, new ContextMenuNeededEventArgs()
                    {
                        Location = PointToClient(_PictureBox.PointToScreen(e.Location)),
                        LocationInBG = e.Location,
                        Rect = _MouseSelectRect,
                        IsInArea = _MouseSelectRect.Left <= e.X && e.X <= _MouseSelectRect.Right && _MouseSelectRect.Top <= e.Y && e.Y <= _MouseSelectRect.Bottom,
                        Control = this
                    });
                }
            }
        }


        private void PictureBox_MouseMove(object sender, MouseEventArgs e)
        {
            if (_IsDrag)
            {
                _MouseSelectRect = Util.GetRectangleByTwoPoint(_MouseDownPos, e.Location);
                _PictureBox.Invalidate();
            }
            BGMouseMove?.Invoke(this, e);
        }

        private void PictureBox_MouseUp(object sender, MouseEventArgs e)
        {
            _IsDrag = false;
            Rectangle rect = Util.GetRectangleByTwoPoint(_MouseDownPos, e.Location);
            if (e.Button == MouseButtons.Left)
            {
                OnSelectedAreaChanged?.Invoke(this, new SelectedAreaChangedEventArgs()
                {
                    Area = rect,
                    Bitmap = BitmapUtils.Clip(_BG, rect)
                });
            }
        }


        private void PictureBox_Paint(object sender, PaintEventArgs e)
        {
            if (!_MouseSelectRect.IsEmpty)
            {
                e.Graphics.DrawRectangle(_SelectPen, _MouseSelectRect);
            }
            BGPaint?.Invoke(this, e);
        }

        #endregion
    }
}
